
/**
 * If source is String - return the function described in it.
 * If source is function - return source.
 */
function getFunction(source){
	if('function'===typeof(source))
		return source;
	else if('string'===typeof(source)){
		var result=window;
		var parts=source.split('.');
		for(var i in parts){
			if('object'===typeof(result))
				result=result[parts[i]];
			else
				return null;
		}
		if('function'===typeof(result))
			return result;
	}
	return null;
}

/**
 * Like getFunction, but returns an array. If the source is string - split by
 * spaces, and each space is a function.
 */
function getFunctions(source){
	if('string'===typeof(source)){
		source=source.split(' ');
	}
	return $.map($.makeArray(source),function(element){return getFunction(element);});
}

/**
 * Escape a String for use in HTML tag properties.
 */
String.prototype.tagpropEscape=function(){
	return this.replace(/&/g,'&amp;')
			   .replace(/"/g,'&quot;')
			   .replace(/</g,'&lt;')
			   .replace(/>/g,'&gt;');
};

/**
 * Escape a String for use in HTML.
 */
String.prototype.htmlEscape=function(){
	return this.replace(/&/g,'&amp;')
			   .replace(/</g,'&lt;')
			   .replace(/>/g,'&gt;');
}

function tagpropEscapeJson(source){
	return JSON.stringify(source).tagpropEscape();
}

/**
 * Return the element targeted in the properties of $(this).
 */
$.fn.targetedElement=function(){
	var thisElement=$(this);
	if(thisElement.is('[selector]')){
		return $(thisElement.attr('selector'));
	}
	if(thisElement.is('[go_up][go_down]')){
		var goUp=thisElement.attr('go_up');
		var upElement=thisElement;
		if(isNaN(goUp)){
			upElement=upElement.closest(goUp);
		}else{
			for(var i=Number(goUp);0<i;--i){
				upElement=upElement.parent();
			}
		}
		return upElement.find(thisElement.attr('go_down'));
	}
}

/**
 * Return the difference in days between two dates.
 */
function dayDiff(fromDay,toDay){
	var msInDay=1000*60*60*24;
	return Math.ceil(new Date(toDay).getTime()/msInDay)-Math.ceil(new Date(fromDay).getTime()/msInDay);
}

/**
 * Splits a controller#method string to [controller,method]
 */
$.fn.controllerAndMethod=function(attribute){
	var attriubteValue=$(this).attr(attribute);
	if(attriubteValue.split){
		return attriubteValue.split('#',2);
	}else{
		return [null,null];
	}
}

/**
 * Collects extra arguments for an element to send in AJAX request.
 */
$.fn.collectExtraArgs=function(){
	var results=[];
	var extraArgsCollector=getFunction($(this).data('extra_args_collector'));
	if(extraArgsCollector){
		results.push(extraArgsCollector.call($(this)));
	}
	var extraArgsJson=$(this).data('extra_args_json');
	if(extraArgsJson){
		results.push(extraArgsJson);
	}
	if(0==results.length){
		return null;
	}else if(1==results.length){
		return results[0];
	}else{
		return $.extend.apply($,results);
	}
}

/**
 * Pad a string from the left.
 */
function padLeft(src,len,chr){
	return src;
	src=src.toString();
	while(len<src.length){
		src=chr+src;
	}
	return src;
}
